﻿using System;
using System.Collections;
using System.Runtime.CompilerServices;

namespace DotNetCommon;

/// <summary>
/// 断言帮助类
/// </summary>
public static class AssertUtil
{
    #region 基础 BeTrue/BeFalse
    /// <summary>
    /// 示例:
    /// <code>
    /// var person = orm.GetById(id);
    /// AssertUtil.BeTrue(person?.IsDelete == false, "数据不存在");
    /// </code>
    /// </summary>
    public static void BeTrue<TException>(bool condition, string errorMessage) where TException : Exception
    {
        if (condition != true) throw (TException)Activator.CreateInstance(typeof(TException), errorMessage);
    }
    /// <summary>
    /// 示例:
    /// <code>
    /// var person = orm.GetById(id);
    /// AssertUtil.BeTrue(person?.IsActive, "数据不存在");
    /// </code>
    /// </summary>
    public static void BeTrue<TException>(bool? condition, string errorMessage) where TException : Exception
    {
        if (condition != true) throw (TException)Activator.CreateInstance(typeof(TException), errorMessage);
    }

    /// <summary>
    /// 示例:
    /// <code>
    /// var person = orm.GetById(id);
    /// AssertUtil.BeTrue(person?.IsDelete == false, "数据不存在");
    /// </code>
    /// </summary>
    public static void BeTrue(bool condition, string errorMessage)
    {
        if (condition != true) throw new Exception(errorMessage);
    }
    /// <summary>
    /// 示例:
    /// <code>
    /// var person = orm.GetById(id);
    /// AssertUtil.BeTrue(person?.IsActive, "数据不存在");
    /// </code>
    /// </summary>
    public static void BeTrue(bool? condition, string errorMessage)
    {
        if (condition != true) throw new Exception(errorMessage);
    }

    /// <summary>
    /// 示例:
    /// <code>
    /// int id;
    /// AssertUtil.BeFalse(id &lt;= 0, "id不正确");
    /// </code>
    /// </summary>
    public static void BeFalse<TException>(bool condition, string message) where TException : Exception
        => BeTrue<TException>(!condition, message);

    /// <summary>
    /// 示例:
    /// <code>
    /// var person = orm.GetById(id);
    /// AssertUtil.BeFalse(person?.IsDelete, "数据不存在");
    /// </code>
    /// </summary>
    public static void BeFalse<TException>(bool? condition, string message) where TException : Exception
        => BeTrue<TException>(!condition, message);

    /// <summary>
    /// 示例:
    /// <code>
    /// int id;
    /// AssertUtil.BeFalse(id &lt;= 0, "id不正确");
    /// </code>
    /// </summary>
    public static void BeFalse(bool condition, string message)
        => BeTrue(!condition, message);
    /// <summary>
    /// 示例:
    /// <code>
    /// var person = orm.GetById(id);
    /// AssertUtil.BeFalse(person?.IsDelete, "数据不存在");
    /// </code>
    /// </summary>
    public static void BeFalse(bool? condition, string message)
        => BeTrue(!condition, message);
    #endregion

    #region NotNull & NotNullOrEmpty & NotNullOrWhiteSpace
    public static void NotNull(object argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument == null) throw new ArgumentNullException(paramName);
    }

    public static void NotNullOrEmpty(string argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument?.Length > 0) return;
        if (argument == null) throw new ArgumentNullException(paramName);
        throw new ArgumentException($"{paramName} 不能为空字符串");
    }

    public static void NotNullOrEmpty(IEnumerable argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument == null) throw new ArgumentNullException(paramName);
        foreach (var item in argument) return;
        throw new ArgumentException($"{paramName} 不能为空集合");
    }

    public static void NotNullOrWhiteSpace(string argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (!string.IsNullOrWhiteSpace(argument)) return;
        if (argument == null) throw new ArgumentNullException(paramName);
        throw new ArgumentException($"{paramName} 不能为空或空白字符串");
    }
    #endregion

    #region 必须为正数(>0)
    public static void GreaterThanZero(int? argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument == null || argument <= 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于 0 !");
    }
    public static void GreaterThanZero(int argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument <= 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于 0 !");
    }
    public static void GreaterThanZero(uint? argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument == null || argument <= 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于 0 !");
    }
    public static void GreaterThanZero(uint argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument <= 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于 0 !");
    }
    public static void GreaterThanZero(short? argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument == null || argument <= 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于 0 !");
    }
    public static void GreaterThanZero(short argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument <= 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于 0 !");
    }
    public static void GreaterThanZero(ushort? argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument == null || argument <= 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于 0 !");
    }
    public static void GreaterThanZero(ushort argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument <= 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于 0 !");
    }
    public static void GreaterThanZero(long? argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument == null || argument <= 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于 0 !");
    }
    public static void GreaterThanZero(long argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument <= 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于 0 !");
    }
    public static void GreaterThanZero(ulong? argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument == null || argument <= 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于 0 !");
    }
    public static void GreaterThanZero(ulong argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument <= 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于 0 !");
    }
    public static void GreaterThanZero(float? argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument == null || argument <= 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于 0 !");
    }
    public static void GreaterThanZero(float argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument <= 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于 0 !");
    }
    public static void GreaterThanZero(double? argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument == null || argument <= 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于 0 !");
    }
    public static void GreaterThanZero(double argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument <= 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于 0 !");
    }
    public static void GreaterThanZero(decimal? argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument == null || argument <= 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于 0 !");
    }
    public static void GreaterThanZero(decimal argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument <= 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于 0 !");
    }
    #endregion

    #region 必须>=0
    public static void GreaterThanOrEuqalToZero(int? argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument == null || argument < 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于等于 0 !");
    }
    public static void GreaterThanOrEuqalToZero(int argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument < 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于等于 0 !");
    }
    public static void GreaterThanOrEuqalToZero(uint? argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument == null || argument < 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于等于 0 !");
    }
    public static void GreaterThanOrEuqalToZero(uint argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument < 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于等于 0 !");
    }
    public static void GreaterThanOrEuqalToZero(short? argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument == null || argument < 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于等于 0 !");
    }
    public static void GreaterThanOrEuqalToZero(short argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument < 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于等于 0 !");
    }
    public static void GreaterThanOrEuqalToZero(ushort? argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument == null || argument < 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于等于 0 !");
    }
    public static void GreaterThanOrEuqalToZero(ushort argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument < 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于等于 0 !");
    }
    public static void GreaterThanOrEuqalToZero(long? argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument == null || argument < 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于等于 0 !");
    }
    public static void GreaterThanOrEuqalToZero(long argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument < 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于等于 0 !");
    }
    public static void GreaterThanOrEuqalToZero(ulong? argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument == null || argument < 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于等于 0 !");
    }
    public static void GreaterThanOrEuqalToZero(ulong argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument < 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于等于 0 !");
    }
    public static void GreaterThanOrEuqalToZero(float? argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument == null || argument < 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于等于 0 !");
    }
    public static void GreaterThanOrEuqalToZero(float argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument < 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于等于 0 !");
    }
    public static void GreaterThanOrEuqalToZero(double? argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument == null || argument < 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于等于 0 !");
    }
    public static void GreaterThanOrEuqalToZero(double argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument < 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于等于 0 !");
    }
    public static void GreaterThanOrEuqalToZero(decimal? argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument == null || argument < 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于等于 0 !");
    }
    public static void GreaterThanOrEuqalToZero(decimal argument, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        if (argument < 0) throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于等于 0 !");
    }
    #endregion

    #region LessThan & LessThanOrEuqalTo & GreaterThan & GreaterThanOrEuqalTo
    public static void LessThan<T>(T argument, T value, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        NotNull(argument, paramName);
        if (argument is null || argument is not IComparable comparable)
            throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须小于 {value} !");
        if (comparable.CompareTo(value) >= 0)
            throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须小于 {value} !");
    }
    public static void LessThanOrEuqalTo<T>(T argument, T value, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        NotNull(argument, paramName);
        if (argument is null || argument is not IComparable comparable)
            throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须小于等于 {value} !");
        if (comparable.CompareTo(value) > 0)
            throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须小于等于 {value} !");
    }
    public static void GreaterThan<T>(T argument, T value, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        NotNull(argument, paramName);
        if (argument is null || argument is not IComparable comparable)
            throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于 {value} !");
        if (comparable.CompareTo(value) <= 0)
            throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于 {value} !");
    }
    public static void GreaterThanOrEuqalTo<T>(T argument, T value, [CallerArgumentExpression(nameof(argument))] string paramName = null)
    {
        NotNull(argument, paramName);
        if (argument is null || argument is not IComparable comparable)
            throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于等于 {value} !");
        if (comparable.CompareTo(value) < 0)
            throw new ArgumentOutOfRangeException(paramName, $"{paramName} 必须大于等于 {value} !");
    }
    #endregion
}
